/**
 * 
 */
package com.liik.game;

import android.graphics.Canvas;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

import com.liik.game.mvc.object.Display;
import com.liik.game.mvc.object.Navigation;
import com.liik.game.util.FPSCounter;
import com.liik.game.util.Vector;

public class GameThread extends Thread implements OnGestureListener, OnDoubleTapListener {

	private final static int MAX_FPS = 60;
	private final static int MAX_FRAME_SKIPS = 20;
	private final static int FRAME_PERIOD = 1000 / MAX_FPS;
	private final static float SCROLL_SPEED = .2f;
	private final static float TILE_TO_PIXEL = 64;

	private FPSCounter fpsCounter;
	private SurfaceHolder surfaceHolder;
	private Navigation navigation;
	private Display display;
	private ScreenHolder screenHolder;
	private boolean isRunning;
	private boolean isPaused; 

	public GameThread(SurfaceHolder surfaceHolder, ScreenHolder screenHolder) {
		super();
		this.surfaceHolder = surfaceHolder;
		this.screenHolder = screenHolder;

		this.fpsCounter = new FPSCounter();
		this.navigation = new Navigation();
		this.display = new Display(TILE_TO_PIXEL, SCROLL_SPEED, surfaceHolder);
		
		this.isRunning = false;
		this.isPaused = false;
	}

	public void setRunning(boolean running) {
		this.isRunning = running;
	}
	
	public void setPaused(boolean paused) {
		this.isPaused = paused;
	}

	@Override
	public void run() {
		Canvas canvas = null;
		long startTime = 0;
		long execTime = 0;
		int sleepTime = 0;
		int skippedFrames = 0;

		while (isRunning) {
			canvas = null;
			try {
				canvas = this.surfaceHolder.lockCanvas();
				if (canvas != null) {
					synchronized (surfaceHolder) {
						startTime = System.currentTimeMillis();
						skippedFrames = 0;
						update();
						render(canvas);
						execTime = System.currentTimeMillis() - startTime;
						sleepTime = (int) (FRAME_PERIOD - execTime);

						if (sleepTime > 0) {
							try {
								Thread.sleep(sleepTime);
							} catch (InterruptedException e) {
							}
						}

						while (sleepTime < 0 && skippedFrames < MAX_FRAME_SKIPS) {
							update();
							sleepTime += FRAME_PERIOD;
							skippedFrames++;
						}
						
						if (skippedFrames == MAX_FRAME_SKIPS) {
							fpsCounter.slowdown = true;
						}
					}
				}
			} finally {
				if (canvas != null) {
					surfaceHolder.unlockCanvasAndPost(canvas);
				}
			}
			
			while (isPaused && isRunning) {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
				}
			}
		}
	}
	
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			screenHolder.popScreen("Back Pressed");
			return true;
		}
		return false;
	}
	
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		return false;
	}

	private synchronized void render(Canvas canvas) {
		screenHolder.render(navigation, display, canvas);
		fpsCounter.update(canvas);
	}

	private synchronized void update() {
		navigation.updateTarget(display);
		screenHolder.update(navigation, display);
	}

	public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		this.surfaceHolder = holder;
		this.display.setScreenSize(width, height);
	}

	public void setSurfaceHolder(SurfaceHolder holder) {
		this.surfaceHolder = holder;
	}
	
	public void onUp(MotionEvent event) {
		navigation.clearScreenTarget();
		navigation.menuTriggered = false;
	}

	@Override
	public boolean onDown(MotionEvent event) {
		// Menu has first priority
		if (screenHolder.handleMenuEvent(event.getX(), event.getY())) {
			navigation.menuTriggered = true;
			return true;
		} 
		navigation.setScreenTarget(event.getX(), event.getY());
		return true;
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {

	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
		if (!navigation.menuTriggered) {
			navigation.setScreenTarget(e2.getX(), e2.getY());
		}
		return true;
	}

	@Override
	public void onShowPress(MotionEvent event) {
		if (!navigation.menuTriggered) {
			navigation.setScreenTarget(event.getX(), event.getY());
		}
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		return false;
	}

	private Vector doubleTapHelper = new Vector();
	
	@Override
	public boolean onDoubleTap(MotionEvent event) {
		doubleTapHelper.set(event.getX(), event.getY());
		display.screenToTile(doubleTapHelper);
		screenHolder.handleDefaultAction(doubleTapHelper.x, doubleTapHelper.y);
		return false;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent e) {
		return false;
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent e) {
		return false;
	}
}
